import store from '@/store/'
import {randomUUID} from '@/utils/util'
// vxe socket
const vs = {
    // 页面唯一 id，用于标识同一用户，不同页面的websocket
    pageId: randomUUID(),
    // webSocket 对象
    ws: null,
    // 一些常量
    constants: {
        // 消息类型
        TYPE: 'type',
        // 消息数据
        DATA: 'data',
        // 消息类型：心跳检测
        TYPE_HB: 'heart_beat',
        // 消息类型：通用数据传递
        TYPE_CSD: 'common_send_date',
        // 消息类型：更新vxe table数据
        TYPE_UVT: 'update_vxe_table',
    },
    // 心跳检测
    heartCheck: {
        // 间隔时间，间隔多久发送一次心跳消息
        interval: 10000,
        // 心跳消息超时时间，心跳消息多久没有回复后重连
        timeout: 6000,
        timeoutTimer: null,
        clear() {
            clearTimeout(this.timeoutTimer)
            return this
        },
        start() {
            vs.sendMessage(vs.constants.TYPE_HB, '')
            // 如果超过一定时间还没重置，说明后端主动断开了
            this.timeoutTimer = window.setTimeout(() => {
                vs.reconnect()
            }, this.timeout)
            return this
        },
        // 心跳消息返回
        back() {
            this.clear()
            window.setTimeout(() => this.start(), this.interval)
        },
    },

    /** 初始化 WebSocket */
    initialWebSocket() {
        if (this.ws === null) {
            const userId = store.getters.userInfo.id
            const domain = window._CONFIG['domianURL'].replace('https://', 'wss://').replace('http://', 'ws://')
            const url = `${domain}/vxeSocket/${userId}/${this.pageId}`

            this.ws = new WebSocket(url)
            this.ws.onopen = this.on.open.bind(this)
            this.ws.onerror = this.on.error.bind(this)
            this.ws.onmessage = this.on.message.bind(this)
            this.ws.onclose = this.on.close.bind(this)

            console.log('this.ws: ', this.ws)
        }
    },

    // 发送消息
    sendMessage(type, message) {
        try {
            let ws = this.ws
            if (ws != null && ws.readyState === ws.OPEN) {
                ws.send(JSON.stringify({
                    type: type,
                    data: message
                }))
            }
        } catch (err) {
            console.warn('【VXEWebSocket】发送消息失败：(' + err.code + ')')
        }
    },

    /** 绑定全局VXE表格 */
    tableMap: new Map(),
    CSDMap: new Map(),
    /** 添加绑定 */
    addBind(map, key, value) {
        let binds = map.get(key)
        if (Array.isArray(binds)) {
            binds.push(value)
        } else {
            map.set(key, [value])
        }
    },
    /** 移除绑定 */
    removeBind(map, key, value) {
        let binds = map.get(key)
        if (Array.isArray(binds)) {
            for (let i = 0; i < binds.length; i++) {
                let bind = binds[i]
                if (bind === value) {
                    binds.splice(i, 1)
                    break
                }
            }
            if (binds.length === 0) {
                map.delete(key)
            }
        } else {
            map.delete(key)
        }
    },
    // 呼叫绑定的表单
    callBind(map, key, callback) {
        let binds = map.get(key)
        if (Array.isArray(binds)) {
            binds.forEach(callback)
        }
    },

    lockReconnect: false,
    /** 尝试重连 */
    reconnect() {
        if (this.lockReconnect) return
        this.lockReconnect = true
        setTimeout(() => {
            if (this.ws && this.ws.close) {
                this.ws.close()
            }
            this.ws = null
            console.info('【VXEWebSocket】尝试重连...')
            this.initialWebSocket()
            this.lockReconnect = false
        }, 5000)
    },

    on: {
        open() {
            console.log('【VXEWebSocket】连接成功')
            this.heartCheck.start()
        },
        error(e) {
            console.warn('【VXEWebSocket】连接发生错误:', e)
            this.reconnect()
        },
        message(e) {
            // 解析消息
            let json
            try {
                json = JSON.parse(e.data)
            } catch (e) {
                console.warn('【VXEWebSocket】收到无法解析的消息:', e.data)
                return
            }
            let type = json[this.constants.TYPE]
            let data = json[this.constants.DATA]
            switch (type) {
                // 心跳检测
                case this.constants.TYPE_HB:
                    this.heartCheck.back()
                    break
                // 通用数据传递
                case this.constants.TYPE_CSD:
                    this.callBind(this.CSDMap, data.key, (fn) => fn.apply(this, data.args))
                    break
                // 更新form数据
                case this.constants.TYPE_UVT:
                    this.callBind(this.tableMap, data.socketKey, (vm) => this.onVM['onUpdateTable'].apply(vm, data.args))
                    break
                default:
                    console.warn('【VXEWebSocket】收到不识别的消息类型:' + type)
                    break
            }
        },
        close(e) {
            console.log('【VXEWebSocket】连接被关闭:', e)
            this.reconnect()
        },
    },

    onVM: {
        /** 收到更新表格的消息 */
        onUpdateTable(row, caseId) {
            // 判断是不是自己发的消息
            if (this.caseId !== caseId) {
                const tableRow = this.getIfRowById(row.id).row
                // 局部保更新数据
                if (tableRow) {
                    // 特殊处理拖轮状态
                    if (row['tug_status'] && tableRow['tug_status']) {
                        row['tug_status'] = Object.assign({}, tableRow['tug_status'], row['tug_status'])
                    }
                    // 判断是否启用重载特效
                    if (this.reloadEffect) {
                        this.$set(this.reloadEffectRowKeysMap, row.id, true)
                    }
                    Object.keys(row).forEach(key => {
                        if (key !== 'id') {
                            this.$set(tableRow, key, row[key])
                        }
                    })
                    this.$refs.vxe.reloadRow(tableRow)
                }
            }
        },
    },

}

export default {
    props: {
        // 是否开启使用 webSocket 无痕刷新
        socketReload: {
            type: Boolean,
            default: false
        },
        socketKey: {
            type: String,
            default: 'vxe-default'
        },
    },
    data() {
        return {}
    },
    mounted() {
        if (this.socketReload) {
            vs.initialWebSocket()
            vs.addBind(vs.tableMap, this.socketKey, this)
        }
    },
    methods: {

        /** 发送socket消息更新行 */
        socketSendUpdateRow(row) {
            vs.sendMessage(vs.constants.TYPE_UVT, {
                socketKey: this.socketKey,
                args: [row, this.caseId],
            })
        },

    },
    beforeDestroy() {
        vs.removeBind(vs.tableMap, this.socketKey, this)
    },
}

/**
 * 添加WebSocket通用数据传递绑定，相同的key可以添加多个方法绑定
 * @param key 唯一key
 * @param fn 当消息来的时候触发的回调方法
 */
export function addBindSocketCSD(key, fn) {
    if (typeof fn === 'function') {
        vs.addBind(vs.CSDMap, key, fn)
    }
}

/**
 * 移除WebSocket通用数据传递绑定
 * @param key 唯一key
 * @param fn 要移除的方法，必须和添加时的方法内存层面上保持一致才可以正确移除
 */
export function removeBindSocketCSD(key, fn) {
    if (typeof fn === 'function') {
        vs.removeBind(vs.CSDMap, key, fn)
    }
}
